import java.util.*;

/**
 * Utility class providing basic factory methods.
 * <p/>
 * The factory methods can be used for common allocation operations related to collections
 * <p/>
 * <code>List<String> merge = CollectionsUtil.makeList();</code>
 * <p/>
 * Use at own risk.
 * Creation data:
 * User: Alex
 * Date: 26/03/12
 * Time: 20:00
 */
public class CollectionsUtil {

    private CollectionsUtil() { }

    /**
     * Returns a typed List implementation
     *
     * @return
     */
    public static <T> List<T> makeList() {
        return new ArrayList<T>(10);
    }

    /**
     * Returns a typed List implementation
     *
     * @param capacity
     * @return
     */
    public static <T> List<T> makeList(int capacity) {
        return new ArrayList<T>(capacity);
    }

    /**
     * Returns a typed List implementation
     *
     * @param in
     * @return
     */
    public static <T> List<T> makeList(final Collection<T> in) {
        int sz = (in == null) ? 10 : in.size();
        final List<T> ret = makeList(sz);
        //
        if (in != null)
            ret.addAll(in);

        return ret;
    }

    /**
     * Returns a typed List implementation initialized with the
     * given values.
     *
     * @param <T>
     * @param args
     */
    public static <T> List<T> makeList(T... args) {
        return asList(args);
    }

    /**
     * Returns a serializable typed Map implementation.
     *
     * @return A typed map.
     */
    public static <K, V> Map<K, V> makeMap() {
        return new HashMap<K, V>(16);
    }

    /**
     * Returns a sorted, typed Map implementation.
     *
     * @return A sorted map implementing the {@link java.util.SortedMap} interface.
     */
    public static <K, V> SortedMap<K, V> makeSortedMap() {
        return makeSortedMap(null);
    }

    /**
     * Returns a sorted, typed Map implementation which uses the passed in <code>Comparator</code>
     * to maintain sorting order.
     *
     * @param c The Comparator to use. This may be <code>null</code>, in which case the Map
     *          will be sorted according to the key's natural ordering.
     * @return A sorted map implementing the {@link java.util.SortedMap} interface.
     */
    public static <K, V> SortedMap<K, V> makeSortedMap(Comparator<K> c) {
        return new TreeMap<K, V>(c);
    }

    /**
     * Returns a typed Set implementation
     *
     * @return
     */
    public static <T> Set<T> makeSet() {
        return makeSet(16);
    }

    public static <T> Set<T> makeSet(int advisorySize) {
        return new HashSet<T>(advisorySize);
    }

    public static <T> Set<T> makeSet(T... args) {
        return makeSet(makeList(args));
    }

    /**
     * Make a Set in which the elements are sorted according to their natural order.
     * Note that this is <strong>not</strong> the same as {@link #makeOrderedSet(int)}, in which
     * only the iteration order is guaranteed to be the same as the insertion order.
     * For this set, the order of iteration is dependent on the element's
     * natural order.
     *
     * @return a generically typed, sorted set.
     */
    public static <T> SortedSet<T> makeSortedSet() {
        return makeSortedSet((Collection<T>) null);
    }

    /**
     * Make a Set in which the elements are sorted according to their natural order.
     * Note that this is <strong>not</strong> the same as {@link #makeOrderedSet(int)}, in which
     * only the iteration order is guaranteed to be the same as the insertion order.
     * For this set, the order of iteration is dependent on the element's
     * natural order.
     *
     * @param c The Collection of elements to initialize the returned sorted set with.
     * @return a generically typed, sorted set.
     */
    public static <T> SortedSet<T> makeSortedSet(Collection<T> c) {
        return makeSortedSet(null, c);
    }

    /**
     * Make a Set in which the elements are sorted according to the supplied Comparator.
     * Note that this is <strong>not</strong> the same as {@link #makeOrderedSet(int)}, in which
     * only the iteration order is guaranteed to be the same as the insertion order.
     * For this set, the order of iteration is dependent on the ordering of the
     * passed in {@link java.util.Comparator}.
     *
     * @param c The comparator to use. As a special case, if <code>null</code> gets passed in,
     *          elements are sorted according to their natural ordering.
     * @return a generically typed, sorted set.
     */
    public static <T> SortedSet<T> makeSortedSet(Comparator<T> c) {
        return makeSortedSet(c, null);
    }

    /**
     * Make a Set in which the elements are sorted according to the supplied Comparator.
     * Note that this is <strong>not</strong> the same as {@link #makeOrderedSet(int)}, in which
     * only the iteration order is guaranteed to be the same as the insertion order.
     * For this set, the order of iteration is dependent on the ordering of the
     * passed in {@link java.util.Comparator}.
     *
     * @param c        The comparator to use. As a special case, if <code>null</code> gets passed in,
     *                 elements are sorted according to their natural ordering.
     * @param elements The elements to initialize the returned sorted set with.
     * @return a generically typed, sorted set.
     */
    public static <T> SortedSet<T> makeSortedSet(Comparator<T> c, Collection<T> elements) {
        TreeSet<T> ts = new TreeSet<T>(c);
        if (elements != null) {
            ts.addAll(elements);
        }
        return ts;
    }

    /**
     * Make a Set guaranteeing the same iteration as insertion order.
     * Note that this is <strong>not</strong> the same as
     * {@link #makeSortedSet()}, which sorts elements according to a
     * comparator and in which the iteration order is dependent on
     * the element's natural order.
     *
     * @return A generically typed, insertion ordered set.
     */
    public static <T> Set<T> makeOrderedSet() {
        return makeOrderedSet(16);
    }

    /**
     * Make a Set guaranteeing the same iteration as insertion order.
     * Note that this is <strong>not</strong> the same as
     * {@link #makeSortedSet()}, which sorts elements according to a
     * comparator and in which the iteration order is dependent on
     * the element's natural order.
     *
     * @param advisorySize the estimated size of the number of elements. Must be
     *                     greater than or equal to zero.
     * @return A generically typed, insertion ordered set.
     */
    public static <T> Set<T> makeOrderedSet(int advisorySize) {
        return new LinkedHashSet<T>(advisorySize);
    }

    /**
     * Make a <code>Map</code> guaranteeing the same iteration as insertion order.
     * Note that this is <strong>not</strong> the same as
     * {@link #makeSortedMap()}, which sorts elements according to a
     * comparator and in which the iteration order is dependent on
     * the element's natural order.
     *
     * @return A generically typed, insertion ordered <code>Map</code>.
     */
    public static <K, V> Map<K, V> makeOrderedMap() {
        return makeOrderedMap(16);
    }

    /**
     * Make a <code>Map</code> guaranteeing the same iteration as insertion order.
     * Note that this is <strong>not</strong> the same as
     * {@link #makeSortedMap()}, which sorts elements according to a
     * comparator and in which the iteration order is dependent on
     * the element's natural order.
     *
     * @param advisorySize the estimated size of the number of elements. Must be greater than
     *                     or equal to zero.
     * @return A generically typed, insertion ordered <code>Map</code>.
     */
    public static <K, V> Map<K, V> makeOrderedMap(int advisorySize) {
        return new LinkedHashMap<K, V>(advisorySize);
    }

    /**
     * Returns a typed Set implementation
     *
     * @param in
     * @return
     */
    public static <T> Set<T> makeSet(final Collection<T> in) {
        int sz = (in == null) ? 16 : in.size();
        final Set<T> ret = new LinkedHashSet<T>(sz);
        //
        if (in != null)
            ret.addAll(in);

        return ret;
    }

    /**
     * Does the same things as Arrays.asList(T ...) except that it returns a Mutable List.
     *
     * @param array
     * @param <T>
     * @return
     */
    public static <T> List<T> asList(T... array) {
        List<T> list = makeList();
        if (array != null)
            list.addAll(Arrays.asList(array));
        return list;
    }
}

